//
// Created by mongobaba on 2021/6/6.
//

#ifndef JSON_VALIDATOR_H
#define JSON_VALIDATOR_H

#include <string>
#include <stdexcept>
#include <cstring>

/**
 * JSON语法规则：https://www.crockford.com/mckeeman.html
 */
class json_validator {
public:
    // 这个版本的构造函数只是为了简化测试代码的编写而存在，正式使用时，
    // 直接调用此版本大概率会发生string对象的复制，对效率有很大影响
    explicit json_validator(std::string json)
            : holder_(std::move(json)), json_(holder_.c_str()), first_(0), last_(holder_.size()) {}

    json_validator(const char *json, std::size_t length)
            : holder_(), json_(json), first_(0), last_(length) {}

    /**
     * 验证json是否合法
     * @param json 要验证的json字符串
     * @return 合法返回true
     */
    static bool validate(const char *json) {
        if (json != nullptr) {
            json_validator validator(json, strlen(json));
            return validator.parse_json();
        }
        return false;
    }

    /**
     * 验证json是否合法
     * @param json 要验证的json字符串
     * @return 合法返回true
     */
    static bool validate(const std::string &json) {
        json_validator validator(json.c_str(), json.size());
        return validator.parse_json();
    }

    /**
     * 解析后的剩余部分
     * @return 剩余部分
     */
    std::string left() const {
        return std::string(json_ + first_, json_ + last_);
    }

    /**
     * 解析sign
     * @return 是否解析成功
     */
    bool parse_sign() {
        read_char('+') || read_char('-');
        return true;
    }

    /**
     * 解析1-9的数字
     * @return 是否解析成功
     */
    bool parse_one_nine() {
        if (first_ < last_) {
            char ch = next_char();
            if (ch >= '1' && ch <= '9') {
                ++first_;
                return true;
            }
        }
        return false;
    }

    /**
     * 解析0-9的数字
     * @return 是否解析成功
     */
    bool parse_digit() {
        if (first_ < last_ && std::isdigit(next_char())) {
            ++first_;
            return true;
        }
        return false;
    }

    /**
     * 解析连续的数字
     * @return 是否解析成功
     */
    bool parse_digits() {
        if (parse_digit()) {
            while (parse_digit()) {}
            return true;
        }
        return false;
    }

    /**
     * 解析十六进制字符
     * @return 是否解析成功
     */
    bool parse_hex() {
        if (first_ < last_ && std::isxdigit(next_char())) {
            ++first_;
            return true;
        }
        return false;
    }

    /**
     * 解析fraction
     * @return 是否解析成功
     */
    bool parse_fraction() {
        if (read_char('.')) {
            return parse_digits();
        }
        return true;
    }

    /**
     * 解析exponent
     * @return 是否解析成功
     */
    bool parse_exponent() {
        if (read_char('E') || read_char('e')) {
            return parse_sign() && parse_digits();
        }
        return true;
    }

    /**
     * 解析integer
     * @return 是否解析成功
     */
    bool parse_integer() {
        // 可有可无的负号
        read_char('-');
        // 保存first_，以便失败后还原
        auto backup = first_;
        // 首先尝试尽可能长的匹配
        if (parse_one_nine() && parse_digits()) {
            return true;
        } else {
            // 如果失败，则还原后尝试另一种可能
            first_ = backup;
            return parse_digit();
        }
    }

    /**
     * 解析number
     * @return 是否解析成功
     */
    bool parse_number() {
        return parse_integer() &&
               parse_fraction() &&
               parse_exponent();
    }

    /**
     * 解析转义字符
     * @return 是否解析成功
     */
    bool parse_escape() {
        if (first_ < last_) {
            switch (next_char()) {
                case 'u':
                    ++first_;
                    for (int i = 0; i < 4; ++i) {
                        if (!parse_hex()) {
                            return false;
                        }
                    }
                    return true;
                case '"':
                case '\\':
                case '/':
                case 'b':
                case 'f':
                case 'n':
                case 'r':
                case 't':
                    ++first_;
                    return true;
                default:
                    return false;
            }
        }
        return false;
    }

    /**
     * 解析whitespace
     * @return 是否解析成功
     */
    bool parse_ws() {
        // 这里直接改为循环，就不用递归了
        while (first_ < last_) {
            switch (next_char()) {
                case '\x20':
                case '\x0a':
                case '\x0d':
                case '\x09':
                    ++first_;
                    break;
                default:
                    return true;
            }
        }
        return true;
    }

    /**
     * 解析character
     * @param meet_string_end 是否因为遇到了字符串结尾而失败
     * @return 是否解析成功
     */
    bool parse_character(bool &meet_string_end) {
        // 默认为false，只有真的遇到字符串结尾才改为true
        meet_string_end = false;
        if (first_ < last_) {
            // 多字节编码时单个char可能为负数，需要转换后再比较
            int ch{static_cast<unsigned char>(next_char())};
            if (ch == '\\') {
                ++first_;
                return parse_escape();
            } else if (ch == '\"') {
                meet_string_end = true;
                return false;
            } else if (ch >= '\x20') {
                ++first_;
                return true;
            }
        }
        return false;
    }

    /**
     * 解析characters
     * @return 是否解析成功
     */
    bool parse_characters() {
        while (first_ < last_) {
            bool meet_string_end = false;
            if (!parse_character(meet_string_end)) {
                // 因遇到字符串结尾而导致的失败不视为解析错误
                return meet_string_end;
            }
        }
        return true;
    }

    /**
     * 解析string
     * @return 是否解析成功
     */
    bool parse_string() {
        return read_char('\"') &&
               parse_characters() &&
               read_char('\"');
    }

    /**
     * 解析true
     * @return 是否解析成功
     */
    bool parse_true() {
        return parse_keyword("true");
    }

    /**
     * 解析false
     * @return 是否解析成功
     */
    bool parse_false() {
        return parse_keyword("false");
    }

    /**
     * 解析null
     * @return 是否解析成功
     */
    bool parse_null() {
        return parse_keyword("null");
    }

    /**
     * 解析string
     * @return 是否解析成功
     */
    bool parse_object() {
        return read_char('{') &&
               parse_ws() &&
               (read_char('}') || (parse_members() && read_char('}')));
    }

    /**
     * 解析array
     * @return 是否解析成功
     */
    bool parse_array() {
        return read_char('[') &&
               parse_ws() &&
               (read_char(']') || (parse_elements() && read_char(']')));
    }

    /**
     * 解析value
     * @return 是否解析成功
     */
    bool parse_value() {
        if (first_ < last_) {
            switch (next_char()) {
                case '{':
                    return parse_object();
                case '[':
                    return parse_array();
                case '\"':
                    return parse_string();
                case 't':
                    return parse_true();
                case 'f':
                    return parse_false();
                case 'n':
                    return parse_null();
                default:
                    return parse_number();
            }
        }
        return false;
    }

    /**
     * 解析element
     * @return 是否解析成功
     */
    bool parse_element() {
        return parse_ws() &&
               parse_value() &&
               parse_ws();
    }

    /**
     * 解析elements
     * @return 是否解析成功
     */
    bool parse_elements() {
        do {
            if (!parse_element()) {
                return false;
            }
        } while (read_char(','));
        return true;
    }

    /**
     * 解析member
     * @return 是否解析成功
     */
    bool parse_member() {
        return parse_ws() &&
               parse_string() &&
               parse_ws() &&
               read_char(':') &&
               parse_element();
    }

    /**
     * 解析members
     * @return 是否解析成功
     */
    bool parse_members() {
        do {
            if (!parse_member()) {
                return false;
            }
        } while (read_char(','));
        return true;
    }

    /**
     * 解析json
     * @return 是否解析成功
     */
    bool parse_json() {
        return parse_element() && first_ >= last_;
    }

private:
    /**
     * 解析关键字（true、false或null）
     * @param str 要解析的关键字
     * @return 是否解析成功
     */
    template<size_t N>
    bool parse_keyword(const char (&str)[N]) {
        constexpr decltype(first_) length = N - 1;
        if (last_ - first_ >= length) {
            if (strncmp(&json_[first_], str, length) == 0) {
                first_ += length;
                return true;
            }
        }
        return false;
    }

    /**
     * 读取下一个字符，并期待其值为ch
     * @param ch 想要读取的值
     * @return 如果读取成功，且值符合预期，则返回true
     */
    bool read_char(char ch) {
        if (first_ < last_ && json_[first_] == ch) {
            ++first_;
            return true;
        }
        return false;
    }

    /**
     * 获取下一个未解析的字符
     * @return 下一个未解析的字符
     */
    char next_char() const {
        if (first_ >= last_) {
            throw std::out_of_range("first_ >= last_ in class json_validator");
        }
        return json_[first_];
    }

private:
    // 测试代码中生成的临时对象保存在holder_中，以避免其失效，正式使用不需要这个成员
    std::string holder_;
    const char *json_;
    std::string::size_type first_;
    const std::string::size_type last_;
};

#endif //JSON_VALIDATOR_H
